﻿using System.Linq.Expressions;
using OpenAiMobile.Database;
using OpenAiMobile.Util.Services;
using Microsoft.EntityFrameworkCore;

namespace OpenAiMobile.Repositories
{
    public abstract class AbsRepository<TEntity> : IRepository<TEntity>
        where TEntity : class
    {
        public SqliteDbContext DbContext { get; }

        public bool AutoDetectChangesEnabled
        {
            get => DbContext.ChangeTracker.AutoDetectChangesEnabled;
            set => DbContext.ChangeTracker.AutoDetectChangesEnabled = value;
        }

        private readonly string _entityName;
        private readonly ILogService _logService;

        protected AbsRepository(
            SqliteDbContext dbContext,
            ILogService logService,
            string entityName
        )
        {
            DbContext = dbContext;
            _logService = logService;
            _entityName = entityName;
        }

        //是否有实体
        public async Task<bool> AnyAsync(Expression<Func<TEntity, bool>> predicate)
        {
            try
            {
                return await DbContext.Set<TEntity>().AnyAsync(predicate);
            }
            catch (Exception e)
            {
                _logService.Error($@"查询{_entityName}是否有数据失败：{e.Message}.");
                return false;
            }
        }

        //获取实体列表
        public async Task<IList<TEntity>> GetAsync(Expression<Func<TEntity, bool>> predicate)
        {
            try
            {
                return await DbContext.Set<TEntity>().Where(predicate).ToListAsync();
            }
            catch (Exception e)
            {
                _logService.Error($@"获取{_entityName}失败：{e.Message}.");
                return new List<TEntity>();
            }
        }

        //获取排序的实体列表
        public async Task<IList<TEntity>> GetAsync<TKey>(
            Expression<Func<TEntity, bool>> predicate,
            Expression<Func<TEntity, TKey>> keySelector,
            bool ascending = true
        )
        {
            try
            {
                return ascending
                    ? await DbContext.Set<TEntity>()
                        .Where(predicate)
                        .OrderBy(keySelector)
                        .ToListAsync()
                    : await DbContext.Set<TEntity>()
                        .Where(predicate)
                        .OrderByDescending(keySelector)
                        .ToListAsync();
            }
            catch (Exception e)
            {
                _logService.Error($@"获取{_entityName}失败：{e.Message}.");
                return new List<TEntity>();
            }
        }

        //获取单个实体
        public async Task<TEntity> GetSingleAsync(Expression<Func<TEntity, bool>> predicate)
        {
            try
            {
                var entityList = await DbContext.Set<TEntity>().Where(predicate).ToListAsync();
                return entityList.SingleOrDefault();
            }
            catch (Exception e)
            {
                _logService.Error($@"获取{_entityName}失败：{e.Message}.");
                return null;
            }
        }

        //获取分页实体
        public async Task<IList<TEntity>> GetPagedAsync<TKey>(
            Expression<Func<TEntity, bool>> predicate,
            Expression<Func<TEntity, TKey>> keySelector,
            int pageIndex,
            int pageSize,
            bool ascending = true
        )
        {
            try
            {
                return ascending
                    ? await DbContext.Set<TEntity>()
                        .Where(predicate)
                        .OrderBy(keySelector)
                        .Skip((pageIndex - 1) * pageSize)
                        .Take(pageSize)
                        .ToListAsync()
                    : await DbContext.Set<TEntity>()
                        .Where(predicate)
                        .OrderByDescending(keySelector)
                        .Skip((pageIndex - 1) * pageSize)
                        .Take(pageSize)
                        .ToListAsync();
            }
            catch (Exception e)
            {
                _logService.Error($@"获取分页{_entityName}失败：{e.Message}.");
                return new List<TEntity>();
            }
        }

        //获取实体个数
        public async Task<int> GetCountAsync(Expression<Func<TEntity, bool>> predicate)
        {
            try
            {
                return await DbContext.Set<TEntity>().CountAsync(predicate);
            }
            catch (Exception e)
            {
                _logService.Error($@"获取{_entityName}个数失败：{e.Message}.");
                return 0;
            }
        }

        //添加实体
        public void Add(TEntity entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            try
            {
                DbContext.Set<TEntity>().Add(entity);
            }
            catch (Exception e)
            {
                _logService.Error($@"添加{_entityName}失败：{e.Message}.");
                throw;
            }
        }

        //批量添加实体
        public void AddRange(IEnumerable<TEntity> entities)
        {
            try
            {
                DbContext.Set<TEntity>().AddRange(entities);
            }
            catch (Exception e)
            {
                _logService.Error($@"批量添加{_entityName}失败：{e.Message}.");
                throw;
            }
        }

        //删除实体
        public void Delete(TEntity entity)
        {
            try
            {
                DbContext.Set<TEntity>().Remove(entity);
            }
            catch (Exception e)
            {
                _logService.Error($@"删除{_entityName}失败：{e.Message}.");
                throw;
            }
        }

        //批量删除实体
        public void DeleteRange(IEnumerable<TEntity> entities)
        {
            try
            {
                DbContext.Set<TEntity>().RemoveRange(entities);
            }
            catch (Exception e)
            {
                _logService.Error($@"批量删除{_entityName}失败：{e.Message}.");
                throw;
            }
        }

        //更新实体
        public void Update(TEntity entity)
        {
            try
            {
                DbContext.Set<TEntity>().Update(entity);
            }
            catch (Exception e)
            {
                _logService.Error($@"更新{_entityName}失败：{e.Message}.");
                throw;
            }
        }

        //更新实体部分属性
        public void Update(TEntity entity, params Expression<Func<TEntity, object>>[] updatedProperties)
        {
            try
            {
                //告诉EF Core开始跟踪实体的更改，
                //因为调用DbContext.Attach方法后，EF Core会将实体的State值
                //更改回EntityState.Unchanged，
                DbContext.Attach(entity);
                if (updatedProperties.Any())
                {
                    foreach (var property in updatedProperties)
                    {
                        //告诉EF Core实体的属性已经更改。将属性的IsModified设置为true后，
                        //也会将实体的State值更改为EntityState.Modified，
                        //这样就保证了下面SaveChanges的时候会将实体的属性值Update到数据库中。
                        DbContext.Entry(entity).Property(property).IsModified = true;
                    }
                }
            }
            catch (Exception e)
            {
                _logService.Error($@"局部更新{_entityName}失败：{e.Message}.");
                throw;
            }
        }

        //批量更新实体
        public void UpdateRange(IEnumerable<TEntity> entities)
        {
            try
            {
                DbContext.Set<TEntity>().UpdateRange(entities);
            }
            catch (Exception e)
            {
                _logService.Error($@"批量更新{_entityName}失败：{e.Message}.");
                throw;
            }
        }

        //保存修改
        public async Task<bool> SaveAsync()
        {
            return await DbContext.SaveChangesAsync() > 0;
        }
    }
}
